package com.aplink.generic.database;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.aplink.generic.controller.GenericApplication;
import com.aplink.generic.dictionary.GenericDictionary;
import com.aplink.generic.pojo.MasterConfig;
import com.aplink.generic.pojo.RecordInfo;
import com.aplink.generic.pojo.TableInfo;
import com.aplink.generic.pojo.TableInit;
import com.aplink.generic.util.LogUtil;
import com.aplink.generic.xmlparser.RecordInfoParser;
import com.aplink.generic.xmlparser.TableInfoParser;

public class DatabaseManager extends SQLiteOpenHelper {
    private static DatabaseManager sInstance = null;

    public static DatabaseManager getInstance() {
        if (DatabaseManager.sInstance == null) {
            DatabaseManager.sInstance = new DatabaseManager(GenericApplication
                    .getInstance().getApplicationContext(), GenericApplication
                    .getInstance().getMasterConfig());
        }
        return DatabaseManager.sInstance;
    }

    private final MasterConfig mMasterConfig;
    private final int mTableDataFileId;
    private final int mTableStructureFileId;

    private ArrayList<RecordInfo> recordInfoList;

    private ArrayList<TableInfo> tableInfoList;

    public DatabaseManager(final Context context,
            final MasterConfig masterConfig) {
        super(context, masterConfig.getDatabaseName(), null, masterConfig
                .getDatabaseVersion());
        this.mTableDataFileId = masterConfig.getDemoDataID(context);
        this.mTableStructureFileId = masterConfig
                .getTableNameStructureID(context);
        this.mMasterConfig = masterConfig;
    }

    private void createTableDemoData(final SQLiteDatabase db) {
        if (this.mTableDataFileId != 0) {
            final GenericDictionary<String, TableInit> tableInits = this.mMasterConfig
                    .getWebserviceConfig().initTableNameInits();
            this.recordInfoList = RecordInfoParser
                    .parseRecordsTables(this.mTableDataFileId);
            final boolean isDemoData = this.mMasterConfig.isDemo();
            try {
                db.beginTransaction();
                for (int i = 0; i < this.recordInfoList.size(); i++) {
                    final RecordInfo recordInfo = this.recordInfoList.get(i);
                    boolean canInitTable = isDemoData;
                    if (!isDemoData) {
                        if (!tableInits.containsKey(recordInfo.getmTableName())) {
                            canInitTable = true;
                        }
                    }
                    if (canInitTable) {
                        initiateTable(db, recordInfo);
                    }
                }
                db.setTransactionSuccessful();
            } catch (final android.database.SQLException e) {
                throw e;
            } finally {
                db.endTransaction();
            }
        }
    }

    private void createTableStructure(final SQLiteDatabase db) {
        if (this.mTableStructureFileId != 0) {
            if (this.mMasterConfig.getTableNameStructure() != null) {
                this.tableInfoList = TableInfoParser
                        .parserTableStructure(this.mTableStructureFileId);
                db.beginTransaction();
                try {
                    for (int i = 0; i < this.tableInfoList.size(); i++) {
                        final TableInfo currentTable = this.tableInfoList
                                .get(i);
                        initiateTableStructure(db, currentTable);
                    }
                    db.setTransactionSuccessful();
                } catch (final android.database.SQLException e) {
                    throw e;
                } finally {
                    db.endTransaction();
                }
            }
        }
    }

    private void initiateTable(final SQLiteDatabase db,
            final RecordInfo recordInfo) {
        for (int recordIndex = 0; recordIndex < recordInfo.getmRecordList()
                .size(); recordIndex++) {
            final ArrayList<Hashtable<String, String>> mRecords = recordInfo
                    .getmRecordList();
            Hashtable<String, String> record = new Hashtable<String, String>();
            record = mRecords.get(recordIndex);
            final ContentValues initialValues = new ContentValues();
            final Enumeration<String> keys = record.keys();
            String key, value;
            while (keys.hasMoreElements()) {
                key = keys.nextElement();
                value = record.get(key);
                initialValues.put(key, value);
            }
            db.insert(recordInfo.getmTableName(), null, initialValues);
        }
    }

    private void initiateTableStructure(final SQLiteDatabase db,
            final TableInfo table) {
        db.execSQL(table.getCreateTableQuery());
        final String message = table.initTableNameName() + " was created";
        LogUtil.info(message, "initiateStructure", getClass());
    }

    public int initTableNameDataFileId() {
        return this.mTableDataFileId;
    }

    public int initTableNameStructureFileId() {
        return this.mTableStructureFileId;
    }

    @Override
    public void onCreate(final SQLiteDatabase db) {
        createTableStructure(db);
        createTableDemoData(db);
    }

    @Override
    public void onDowngrade(final SQLiteDatabase db, final int oldVersion,
            final int newVersion) {
        super.onDowngrade(db, oldVersion, newVersion);
    }

    @Override
    public void onUpgrade(final SQLiteDatabase db, final int oldVersion,
            final int newVersion) {
        super.onDowngrade(db, oldVersion, newVersion);
    }
}
